﻿namespace Atomic.Caching
{
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;

    /// <summary>
    /// 默认缓存管理器。
    /// </summary>
    public class DefaultCacheManager : ICacheManager
    {
        /// <summary>
        /// 静态字典缓存数据。
        /// </summary>
        private readonly static IDictionary<string, CacheEntity> _cache = new Dictionary<string, CacheEntity>();

        /// <summary>
        /// 锁定对象。
        /// </summary>
        private static object lockobject = new object();

        /// <summary>
        /// 获取缓存值。
        /// </summary>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="key">键对象</param>
        /// <returns>值对象</returns>
        public TValue Get<TValue>(string key)
        {
            if (_cache.ContainsKey(key))
            {
                var cache = _cache[key];

                if (cache.ExpiredTime > DateTime.UtcNow)
                {
                    return (TValue)cache.Value;
                }
            }

            return default(TValue);
        }

        /// <summary>
        /// 获取缓存值，如果不存在，则添加缓存。
        /// </summary>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="key">键对象</param>
        /// <param name="acquire">获得值对象的委托。</param>
        /// <returns>值对象。</returns>
        public TValue GetOrAdd<TValue>(string key, Func<TValue> acquire)
        {
            var result = this.Get<TValue>(key);

            if (result == null)
            {
                result = acquire();

                this.Set(key, result);
            }

            return result;
        }

        /// <summary>
        /// 增加缓存值。
        /// </summary>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="key">键对象</param>
        /// <param name="value">值对象</param>
        public void Set<TValue>(string key, TValue value)
        {
            this.Set<TValue>(key, value, DateTime.UtcNow.AddMinutes(20));
        }

        /// <summary>
        /// 增加缓存值。
        /// </summary>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="key">键对象</param>
        /// <param name="value">值对象</param>
        /// <param name="expiredTime">过期时间(UTC)。</param>
        public void Set<TValue>(string key, TValue value, DateTime expiredTime)
        {
            if (value != null)
            {
                CacheEntity cache = new CacheEntity
                {
                    Value = value,
                    ExpiredTime = expiredTime
                };
                
                lock (lockobject)
                {
                    _cache[key] = cache;
                }
            }
        }

        /// <summary>
        /// 移除缓存值。
        /// </summary>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="key">键对象</param>
        /// <param name="result">值对象</param>
        public void Remove<TValue>(string key, out TValue result)
        {
            result = default(TValue);

            if (_cache.ContainsKey(key))
            {
                result = (TValue)_cache[key].Value;

                _cache.Remove(key);
            }
        }

        /// <summary>
        /// 清空缓存。
        /// </summary>
        public void Clear()
        {
            _cache.Clear();
        }

        /// <summary>
        /// 缓存实体。
        /// </summary>
        private class CacheEntity
        {
            /// <summary>
            /// 缓存值。
            /// </summary>
            public object Value { get; set; }

            /// <summary>
            /// 过期时间（UTC）
            /// </summary>
            public DateTime ExpiredTime { get; set; }
        }
    }
}